package wrm.saferJava.aop.oval;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


import org.aopalliance.intercept.ConstructorInvocation;
import org.aopalliance.intercept.MethodInvocation;
import org.objectweb.asm.ClassVisitor;

import wrm.saferJava.aop.InjectorBinding;
import wrm.saferJava.oval.guard.Guard;
import wrm.saferJava.oval.guard.GuardInterceptor;


public class OvalAopAdvice {



	
	private static class MethodCall implements MethodInvocation
	{
		private Object proxy;
		private Method method;
		private Object[] args;
		private Method mProxy;
		
		public MethodCall(Object proxy, Method method, Object[] args, Method mProxy) {
			super();
			this.proxy = proxy;
			this.method = method;
			this.args = args;
			this.mProxy = mProxy;
		}

		
		@Override
		public Object[] getArguments() {
			return args;
		}

		@Override
		public AccessibleObject getStaticPart() {
			return null;
		}

		@Override
		public Object getThis() {
			return proxy;
		}

		@Override
		public Object proceed() throws Throwable {
			
			try{
				return mProxy.invoke(proxy, args);
			}
			catch (InvocationTargetException e) {
				//was thrown during execution of mProxy.
				//rethrow cause
				throw e.getCause();
			}
			
		}

		@Override
		public Method getMethod() {
			return method;
		}
		
	}
	
	
	private static class ConstructorCall implements ConstructorInvocation
	{

		private final Object proxy;
		private final Constructor c;
		private final Object[] args;

		public ConstructorCall(Object proxy, Constructor c, Object[] args) {
			this.proxy = proxy;
			this.c = c;
			this.args = args;
		}

		@Override
		public Object[] getArguments() {
			return args;
		}

		@Override
		public AccessibleObject getStaticPart() {
			return null;
		}

		@Override
		public Object getThis() {
			return proxy;
		}

		@Override
		public Object proceed() throws Throwable {
			//dont do anything here
			return null;
		}

		@Override
		public Constructor getConstructor() {
			return c;
		}
		
	}



//	public Object intercept(Object proxy, Method method, Object[] args,
//			Method mProxy) throws Throwable {
//		// call 
//		MethodCall mc = new MethodCall(proxy, method, args, mProxy);
//		Object result = this.invoke(mc);
//		
//		return result;
//	}

	private static GuardInterceptor _interceptor_instance = new GuardInterceptor();
	public static Object intercept(Object proxy, String method, Class[] argClass, Object[] args) throws Throwable {
		// call 
		
		//is it constructor?
		if (method.equals("<init>"))
		{
			Constructor c = proxy.getClass().getConstructor(argClass);
			ConstructorCall cc = new ConstructorCall(proxy, c, args);
			
			Object result = _interceptor_instance.construct(cc);
			return result; //will be null as this is only a workaround because no 
							//REAL constructor around advice is possible 
							//(i know, its possible, but i dont have time for this ;D)
			
			
		}
		
		
		Method m = proxy.getClass().getMethod(method, argClass);
		Method mP = proxy.getClass().getMethod(method + OvalGuardInjector.METHOD_PROXY_QUALIFIER, argClass);
		
		MethodCall mc = new MethodCall(proxy, m, args, mP);
		Object result = _interceptor_instance.invoke(mc);
		
		return result;
	}
}
